package service

import (
	"automation/util"
	"fmt"
	"log"
	"math/rand"
	"strings"
	"time"

	"github.com/pkg/errors"
	"github.com/tebeka/selenium"
)

type Reliste struct {
}

func (s Reliste) Start() {
	driver := SetupDriver()
	defer server.Stop()
	defer driver.Quit()

	s.fetchList(driver)
}

func (s Reliste) fetchList(driver selenium.WebDriver) {
	for {
		err := s.loopList(driver)
		if err != nil {
			if errors.Is(err, ErrorNotFound) {
				log.Fatal(err.Error())
			}
			fmt.Println(err.Error())
			// 刷新页面
			refreshPage(driver)
		} else {
			// 跳转页面后继续刷新
			originalWindow, _ := driver.CurrentWindowHandle()
			// 跳转页面
			redirect(driver, originalWindow)
		}

		s.fetchList(driver)
	}
}

// 遍历列表
func (s Reliste) loopList(driver selenium.WebDriver) error {
	//打开列表页
	err := driver.Get(util.Viper.GetString("reliste.url"))
	if err != nil {
		return errors.Wrap(err, "打开列表页失败")
	}

	//轮询等待页面加载完成
	err = driver.WaitWithTimeout(func(wd selenium.WebDriver) (bool, error) {
		_, err := driver.FindElements(selenium.ByCSSSelector, "table.ItemTable > tbody > tr")
		//元素未找到，继续等待
		if err != nil {
			return false, nil
		}
		return true, nil
	}, time.Second*60)
	if err != nil {
		return errors.Wrap(err, "商品列表页面加载超时")

	}

	elements, err := driver.FindElements(selenium.ByCSSSelector, "table.ItemTable > tbody > tr")
	if err != nil {
		return errors.Wrap(err, "获取列表节点失败")
	}

	if len(elements) < 2 {
		return errors.Wrap(ErrorNotFound, "未发现需要重新上架的商品或重试")
	}

	//从第二行开始遍历
	e := elements[1]

	//商品标题
	titleElement, err := e.FindElement(selenium.ByCSSSelector, "td:nth-child(3) > a")
	if err != nil {
		return errors.Wrap(err, "获取标题节点失败")
	}

	title, err := titleElement.Text()
	if err != nil {
		return errors.Wrap(err, "获取商品标题失败")
	}
	fmt.Printf("正在重新上架商品: %s\n", title)

	//重新上架按钮
	btnElement, err := e.FindElement(selenium.ByCSSSelector, "td:last-child>a")
	if err != nil {
		return errors.Wrap(err, "获取按钮节点失败")
	}

	//重新上架
	return s.resubmit(driver, btnElement)
}

// 重新上架
func (s Reliste) resubmit(driver selenium.WebDriver, element selenium.WebElement) error {
	//点击重新上架按钮
	err := element.Click()
	if err != nil {
		return errors.Wrap(err, "点击重新上架按钮失败")
	}

	t := util.Viper.GetUint("reliste.form_page_load_timeout")
	if t == 0 {
		t = 10
	}
	time.Sleep(time.Second * time.Duration(t)) //等待页面加载完成

	//轮询等待页面加载完成
	err = driver.WaitWithTimeout(func(wd selenium.WebDriver) (bool, error) {
		readyState, err := driver.ExecuteScript("return document.readyState", nil)
		//元素未找到，继续等待
		if err != nil {
			return false, nil
		}
		return readyState.(string) == "complete", nil
	}, time.Second*120)
	if err != nil {
		return errors.Wrap(err, "打开再出品页面加载超时")
	}

	//商品状态异常
	_, err = driver.FindElement(selenium.ByID, "modAlertBox")
	if err == nil {
		return errors.Wrap(err, "商品状态异常，请手动处理")
	}

	//对话框
	dialog, err := driver.FindElement(selenium.ByCSSSelector, ".PayPayMaturiModal")
	if err == nil {
		//检查class里是否包含is-show
		class, err := dialog.GetAttribute("class")
		if err != nil {
			return errors.Wrap(err, "获取对话框class属性失败")
		}
		//包含 is-show
		if strings.Contains(class, "is-show") {
			_, err = driver.ExecuteScript("arguments[0].classList.remove('is-show')", []interface{}{dialog})
			if err != nil {
				return errors.Wrap(err, "关闭对话框失败")
			}
		}

	}

	//提示是否确认
	dialog, err = driver.FindElement(selenium.ByID, "insertion_dlg")
	if err == nil {
		//检查style="display: none;"
		style, err := dialog.GetAttribute("style")
		if err != nil {
			return errors.Wrap(err, "获取对话框style属性失败")
		}
		if style != "display: none;" {
			d, err := driver.FindElement(selenium.ByID, "auc_insertion_ok")
			if err != nil {
				return errors.Wrap(err, "获取确认按钮节点失败")
			}
			err = d.Click()
			if err != nil {
				return errors.Wrap(err, "点击确认按钮失败")
			}
		}
	}

	//滚动到底部
	js := `window.scrollTo(0, document.body.scrollHeight);`
	_, err = driver.ExecuteScript(js, nil)
	if err != nil {
		return errors.Wrap(err, "滚动到底部失败")
	}

	//日期选择
	err = driver.WaitWithTimeout(func(wd selenium.WebDriver) (bool, error) {
		_, err := driver.FindElement(selenium.ByID, "ClosingYMD")
		//元素未找到，继续等待
		if err != nil {
			return false, nil
		}
		return true, nil
	}, time.Second*120)
	if err != nil {
		return errors.Wrap(err, "打开再出品页面加载超时")
	}

	//日期选择
	we, err := driver.FindElement(selenium.ByID, "ClosingYMD")
	if err != nil {
		return errors.Wrap(err, "获取日期选择节点失败")
	}

	we.Click()

	//是否指定日期选项
	specifyDateOption := util.Viper.GetBool("reliste.specify_date_option")
	if specifyDateOption {
		index := util.Viper.GetUint("reliste.date_option_index")
		if index == 0 {
			index = 1
		}

		//选择第二项option
		we, err = driver.FindElement(selenium.ByCSSSelector, fmt.Sprintf("#ClosingYMD >option:nth-child(%d)", index))
		if err != nil {
			return errors.Wrap(err, "获取日期选择节点选项失败")
		}
		we.Click()
	}

	specifyTimeOption := util.Viper.GetBool("reliste.specify_time_option")
	if specifyTimeOption {
		//结束时间选择
		we, err = driver.FindElement(selenium.ByID, "ClosingTime")
		if err != nil {
			return errors.Wrap(err, "获取结束时间选择节点失败")
		}
		we.Click()

		//生成18-24的随机数，索引从1开始
		//hour := 1 + rand.Intn(6) + 18

		indexArr := util.Viper.GetIntSlice("reliste.time_option_index_range")
		hour := 1 + rand.Intn(indexArr[1]-indexArr[0]) + indexArr[0]

		//选择下午6点到11点
		we, err = driver.FindElement(selenium.ByCSSSelector, fmt.Sprintf("#ClosingTime >option:nth-child(%d)", hour))
		if err != nil {
			return errors.Wrap(err, "获取结束时间选择节点选项失败")
		}

		v, err := we.Text()
		if err != nil {
			return errors.Wrap(err, "获取结束时间选择节点选项值失败")
		}
		fmt.Println("时间选择:", v)
		we.Click()
	}

	//提交按钮
	we, err = driver.FindElement(selenium.ByID, "submit_form_btn")
	if err != nil {
		return errors.Wrap(err, "获取提交按钮节点失败")
	}
	err = we.Click()
	if err != nil {
		return errors.Wrap(err, "点击提交按钮失败")
	}
	//time.Sleep(time.Second * 5) //等待页面加载完成

	//确认
	return s.confirm(driver)
}

// 确认
func (s Reliste) confirm(driver selenium.WebDriver) error {
	//提示框
	//商品未过期
	_, err := driver.FindElement(selenium.ByID, "modAlertBox")
	if err == nil {
		return errors.Wrap(err, "商品状态异常，请手动处理")
	}

	//商品未过期
	_, err = driver.FindElement(selenium.ByID, "yjMain")
	if err == nil {
		return errors.Wrap(err, "商品状态异常，请手动处理")
	}

	//轮询等待页面加载完成
	err = driver.WaitWithTimeout(func(wd selenium.WebDriver) (bool, error) {
		_, err := driver.FindElement(selenium.ByID, "auc_preview_submit_down")
		//元素未找到，继续等待
		if err != nil {
			return false, nil
		}
		return true, nil
	}, time.Second*60)
	if err != nil {
		return errors.Wrap(err, "打开确认页面加载超时")
	}

	we, err := driver.FindElement(selenium.ByID, "auc_preview_submit_down")
	if err != nil {
		return errors.Wrap(err, "获取确认按钮节点失败")
	}
	we.Click()
	//time.Sleep(time.Second * 2) //等待页面加载完成

	//轮询等待页面加载完成
	err = driver.WaitWithTimeout(func(wd selenium.WebDriver) (bool, error) {
		_, err := driver.FindElement(selenium.ByID, "modTitBar")
		//元素未找到，继续等待
		if err != nil {
			return false, nil
		}
		return true, nil
	}, time.Second*60)
	if err != nil {
		return errors.Wrap(err, "打开完成页面加载超时")
	}

	fmt.Println("商品上架成功...")

	return nil
}
